/*
 * %W% %E% 		
 */
package com.vinhvt.effiport.util;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;

import com.vinhvt.effiport.algorithm.genetic.*;
import com.vinhvt.effiport.financial.ep.*;

public class Helper {
	
	/**
	 * Convert a boolean array (binary) to decimal.
	 * 
	 * @param bits the bits
	 * 
	 * @return the number
	 */
	public static Number toDecimal(boolean[] bits) {
		int result = 0;
		
		for(int i = 0; i < bits.length; i++) {
			result += (bits[i] ? 1 : 0) * Math.pow(2, bits.length - i - 1); 
		}
		
		return result;
	}
	
	/**
	 * Generate Bits Randomly but It's Decimal Value is not over Range Value.
	 * 
	 * @param po the po
	 * @param length the length
	 * @param range the range
	 * 
	 * @return the boolean[]
	 * 
	 * @throws InterruptedException the interrupted exception
	 */
	public static boolean[] generateBits(double po, int length, int range) throws InterruptedException {
		boolean[] bits = new boolean[length];
		do {
			Random random = new Random();
			for(int i = 0; i < length; i++) {
				double randDouble = random.nextDouble();
				Thread.sleep(5);
				bits[i] = (randDouble < po);
			}
		} while (toDecimal(bits).intValue() > range);
		
		return bits;
	}
	
	public static boolean[] generateBits(double po, int length) throws InterruptedException {
		boolean[] bits = new boolean[length];
		Random random = new Random();
		for(int i = 0; i < length; i++) {
			double randDouble = random.nextDouble();
			Thread.sleep(2);
			bits[i] = (randDouble < po);
		}
		return bits;
	}
	
	
	/**
	 * Extend the first boolean array by concatenating the second array to the first array.
	 * 
	 * @param first the first
	 * @param second the second
	 * 
	 * @return the boolean[]
	 */
	public static boolean[] extend(boolean[] first, boolean[] second) {
		if (first == null && second != null) return second;		
		if (first != null && second == null) return first;
				
		int length = first.length + second.length;
		
		boolean[] result = new boolean[length];
		
		for(int i = 0; i < first.length; i++) {
			result[i] =  first[i];
		}
		
		for(int i = 0; i < second.length; i++) {
			result[i + first.length] = second[i];
		}
		
		return result;
	}
	
	 public static int GetPosition(double value, double[] array)
     {
         //The following Code should be replaced by Binary Seaching
         int result = 0;
         for (int i = 0; i < array.length; i++)
         {
             if (value < array[i])
             {
                 result = i;
                 break;
             }
         }
         return result;
     }
	 
	 public static String toBits(boolean[] bits) {
		 String result = "";
		 
		 for(int i = 0; i < bits.length; i++) {
			 result += bits[i] ? "1" : "0";
		 }
		 
		 return result;
	 }
	 
	 public static List<Double> buildRateOfReturnList(List<Double> lstClosedPrice) {
		 List<Double> result = new ArrayList<Double>();
		 
		 result.add(0.0);
		 int times = lstClosedPrice.size();
			for(int i = 1 ; i< times; i++) {
				double p0 = lstClosedPrice.get(i-1);
				double p1 = lstClosedPrice.get(i);
				Double tmp = (p1 - p0)/p0 * 100;
				BigDecimal bd = new BigDecimal(tmp, new MathContext(2, RoundingMode.HALF_UP));				
				result.add(bd.doubleValue());
			}
		 
		 return result;
	 }
	 
	 public static List<Transaction> refillTransactionInMode(List<Transaction> trans, int mode) {
		 List<Transaction> result = new ArrayList<Transaction>();			
		 
		 if(mode == GAsParameters.MODE_MONTH) {
			 //load only transaction in the last day of month				
			 for(int i = 0; i < trans.size() - 1; i++) {
				 Date before = trans.get(i).getDate();					
			
				 Calendar calBefore = Calendar.getInstance();
				 calBefore.setTime(before);					
						
				 Date after = trans.get(i + 1).getDate();
				 Calendar calAfter = Calendar.getInstance();
				 calAfter.setTime(after);
			
				 if (calAfter.get(Calendar.MONTH) > calBefore.get(Calendar.MONTH)) {
					 result.add(trans.get(i));
				 }				
			 }
			 
			 result.add(trans.get(trans.size() - 1));
		}
		
		return result;
	 }	 
	 
	 public static Portfolio filter(Portfolio port) {
		 Portfolio result = null;
		 
		 List<String> ticker = new ArrayList<String>();
		 List<Double> weight = new ArrayList<Double>();
		 
		 for(int i = 0; i < port.getNumberOfAsset(); i++) {
			 Asset asset = port.getAssetAt(i);
			 ticker.add(asset.getSymbol());
			 weight.add(asset.getWeight());
		 }
		 
		 int i = 0;
		 while(port.getTotalWeight() == 0) {
			 Asset asset = port.getAssetAt(i);
		 }
		 
		 return result;
	 }
	 
	 public static double round(double value) {
		 double result = 0.0;
		 
		 DecimalFormat two = new DecimalFormat("#.####");
		 
		 result = Double.valueOf(two.format(value));		 
		 
		 return result;
	 }
	 
	 public static long formatNumber(String value) {
		 long result = 0;
		 
		 	//String myString = NumberFormat.getInstance().fo
		 return result;
		 
		 
	 }
}
